﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using HtmlAgilityPack;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml;


namespace IndustrialMusicWindowsCSharp {
    public partial class ConvertScreenScrapes : Form {
        //private const string filePrefix = "Artists_";
        //private const string fileExt = ".txt";
        //XmlConversionProgressForm progressForm;

        public ConvertScreenScrapes() {
            InitializeComponent();
            conversionFolderDialog.RootFolder = Environment.SpecialFolder.MyComputer;
            conversionFolderDialog.ShowNewFolderButton = true;
        }

        private void btnConversionFolderSelect_Click(object sender, EventArgs e) {
            DialogResult result = conversionFolderDialog.ShowDialog();
            if (result == DialogResult.OK) {
                txtConversionFolder.Text = conversionFolderDialog.SelectedPath;
            }
        }

        private void btnSelectDestination_Click(object sender, EventArgs e) {
            DialogResult result = conversionFolderDialog.ShowDialog();
            if (result == DialogResult.OK) {
                txtConversionDestinationFolder.Text = conversionFolderDialog.SelectedPath;
            }
        }

        private void btnCancel_Click(object sender, EventArgs e) {
            conversionBackgroundWorker.CancelAsync();
            this.Close();
        }

        private void btnConvert_Click(object sender, EventArgs e) {
            conversionBackgroundWorker.RunWorkerAsync(txtConversionFolder.Text);
        }

        private void ProcessFiles(string directoryPath) {
            DirectoryInfo directory = new DirectoryInfo(directoryPath);
            XmlDataDocument xmlDocument = GetEmptyXmlDocument();

            if (directory.GetFiles().Length > 0) {
                foreach (FileInfo file in directory.GetFiles()) {
                    string filePath = file.Directory + @"\" + file.Name;
                    HtmlAgilityPack.HtmlDocument htmlDocument = GetWebDocument(filePath);
                    ProcessDocument(htmlDocument, xmlDocument);
                }
            }
        }

        private HtmlAgilityPack.HtmlDocument GetWebDocument(string filePath) {
            //  Get file contents
            StreamReader reader = new StreamReader(filePath);
            string pageContents = reader.ReadToEnd();

            //  Remove all carriage returns
            Regex carriageReturns = new Regex("\r\n");
            pageContents = carriageReturns.Replace(pageContents, string.Empty);

            //  Clean up
            reader.Close();
            reader.Dispose();

            //  Create
            HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();

            document.LoadHtml(pageContents);

            return document;
        }

        private XmlDataDocument GetEmptyXmlDocument() {
            XmlDataDocument xmlDocument = new XmlDataDocument();
            xmlDocument.LoadXml("<?xml version='1.0' ?><Artists/>");

            return xmlDocument;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="htmlDocument"></param>
        /// <param name="xmlDocument"></param>
        private void ProcessDocument(HtmlAgilityPack.HtmlDocument htmlDocument, XmlDataDocument xmlDocument) {
            //  Select table rows that contain all information
            HtmlNodeCollection rows = htmlDocument.DocumentNode.SelectNodes("//tr");
            XmlNode artistNode = null;

            //  Iterate over rows and parse out data.
            foreach (HtmlNode row in rows) {
                HtmlNode node = row.SelectSingleNode("td");

                if (node.Attributes.Count != 0) {
                    //  Get the class to determine what kind of data retrieved.
                    string nodeClass = node.Attributes["class"].Value;

                    //  If artistheader, we have a group.
                    //  If artistitem, we have either a release, a compilation, or links.
                    //  If artistdate, we have notes about the artist.
                    if (nodeClass == "artistheader") {
                        //  Process Artists
                        artistNode = xmlDocument.CreateNode(XmlNodeType.Element, "Artist", String.Empty);
                        XmlAttribute artistName = (XmlAttribute)xmlDocument.CreateNode(XmlNodeType.Attribute, "name", string.Empty);
                        artistName.Value = node.InnerText.Trim();
                        artistNode.Attributes.Append(artistName);
                        xmlDocument.DocumentElement.AppendChild(artistNode);
                    } else if (nodeClass == "artistitem") {
                        switch (node.InnerText.Trim()) {
                            case "Releases":
                                HtmlNode releasesHtmlNode = node.NextSibling;

                                XmlNode releasesNode = xmlDocument.CreateNode(XmlNodeType.Element, "Releases", string.Empty);

                                ProcessReleases(xmlDocument, releasesNode, releasesHtmlNode);

                                artistNode.AppendChild(releasesNode);

                                break;
                            case "Compilations":
                                //  Process Compilations
                                HtmlNode compilationsHtmlNode = node.NextSibling;

                                XmlNode compilationsNode = xmlDocument.CreateNode(XmlNodeType.Element, "Compilations", string.Empty);

                                ProcessCompilations(xmlDocument, compilationsNode, compilationsHtmlNode);

                                artistNode.AppendChild(compilationsNode);

                                break;
                            case "Other Links":
                                //  Process Links
                                HtmlNode linksHtmlNode = node.NextSibling;

                                XmlNode linksNode = xmlDocument.CreateNode(XmlNodeType.Element, "Links", string.Empty);

                                ProcessLinks(xmlDocument, linksNode, linksHtmlNode);

                                artistNode.AppendChild(linksNode);
                                break;
                        }
                    } else if (nodeClass == "artistdata") {
                        //  Process artists data
                        XmlNode artistDataNode = xmlDocument.CreateNode(XmlNodeType.Element, "ArtistData", string.Empty);

                        artistDataNode.InnerText = node.InnerText.Trim();
                        artistNode.AppendChild(artistDataNode);
                    }
                }

                string blah = string.Empty;
            }

            //  Write the Xml out to a file.
            if (txtConversionDestinationFolder.Text.Length != 0) {
                if (Directory.Exists(txtConversionDestinationFolder.Text)) {
                    XmlTextWriter xmlWriter = new XmlTextWriter(txtConversionDestinationFolder.Text + @"\industrialmusicdatabase.xml", Encoding.Unicode);
                    xmlDocument.WriteContentTo(xmlWriter);
                    xmlWriter.Flush();
                    xmlWriter.Close();
                } else {
                    MessageBox.Show("Directory does not exist.");
                }
            } else {
                MessageBox.Show("The destination Folder cannot be empty.");
            }
        }

        private void ProcessLinks(XmlDataDocument xmlDocument, XmlNode linksNode, HtmlNode linksHtmlNode) {
            if (linksHtmlNode.ChildNodes.Count > 0) {
                HtmlNodeCollection linksCollection = linksHtmlNode.ChildNodes;

                foreach (HtmlNode link in linksCollection) {
                    Regex linkRegEx = new Regex(@"\<li\>\<a href=\x22(.*?)\x22\>(.*?)\<\/a\>");
                    MatchCollection linkMatches = linkRegEx.Matches(link.OuterHtml);

                    XmlNode linkNode = null;
                    foreach (Match match in linkMatches) {
                        linkNode = xmlDocument.CreateNode(XmlNodeType.Element, "Link", string.Empty);

                        if (match.Groups.Count > 0) {

                            XmlAttribute hrefNode = (XmlAttribute)xmlDocument.CreateNode(XmlNodeType.Attribute, "href", string.Empty);
                            XmlAttribute textNode = (XmlAttribute)xmlDocument.CreateNode(XmlNodeType.Attribute, "text", string.Empty);

                            hrefNode.Value = match.Groups[1].Value.Trim();
                            textNode.Value = match.Groups[2].Value.Trim();
                            linkNode.Attributes.Append(hrefNode);
                            linkNode.Attributes.Append(textNode);
                        }

                        linksNode.AppendChild(linkNode);
                    }
                }
            }
        }

        private void ProcessReleases(XmlDataDocument xmlDocument, XmlNode releasesNode, HtmlNode releasesHtmlNode) {
            if (releasesHtmlNode.ChildNodes.Count > 0) {
                HtmlNodeCollection releasesCollection = releasesHtmlNode.ChildNodes;

                foreach (HtmlNode release in releasesCollection) {
                    Regex releaseRegEx = new Regex(@"\<li\>\<i\>(.*?)<\/i\>(.*?)\(((.*?)(\d{4}))|(\d{4})\)");
                    MatchCollection releaseMatches = releaseRegEx.Matches(release.OuterHtml);

                    XmlNode releaseNode = null;
                    foreach (Match match in releaseMatches) {
                        releaseNode = xmlDocument.CreateNode(XmlNodeType.Element, "Release", string.Empty);

                        if (match.Groups.Count > 0) {

                            XmlNode titleNode = xmlDocument.CreateNode(XmlNodeType.Element, "Title", string.Empty);
                            XmlNode formatNode = xmlDocument.CreateNode(XmlNodeType.Element, "Format", string.Empty);
                            XmlNode releaseDateNode = xmlDocument.CreateNode(XmlNodeType.Element, "ReleaseDate", string.Empty);
                            XmlNode labelNode = xmlDocument.CreateNode(XmlNodeType.Element, "Label", string.Empty);

                            titleNode.InnerText = match.Groups[1].Value.Trim();
                            formatNode.InnerText = match.Groups[2].Value.Trim();

                            if (match.Groups[3].Length > 4) {
                                labelNode.InnerText = match.Groups[4].Value.Trim();
                                releaseDateNode.InnerText = match.Groups[5].Value.Trim();
                            } else {
                                labelNode.InnerText = string.Empty;
                                releaseDateNode.InnerText = match.Groups[3].Value.Trim();
                            }

                            releaseNode.AppendChild(titleNode);
                            releaseNode.AppendChild(formatNode);
                            releaseNode.AppendChild(labelNode);
                            releaseNode.AppendChild(releaseDateNode);

                        }

                        releasesNode.AppendChild(releaseNode);
                    }
                }
            }
        }

        private void ProcessCompilations(XmlDataDocument xmlDocument, XmlNode releasesNode, HtmlNode releasesHtmlNode) {
            if (releasesHtmlNode.ChildNodes.Count > 0) {
                HtmlNodeCollection releasesCollection = releasesHtmlNode.ChildNodes;

                foreach (HtmlNode release in releasesCollection) {
                    Regex releaseRegEx = new Regex(@"\<li\>\<i\>\<a.*?\>(.*?)\<\/a\><\/i\>(.*?)\(((.*?)(\d{4}))|(\d{4})\)");
                    MatchCollection releaseMatches = releaseRegEx.Matches(release.OuterHtml);

                    XmlNode releaseNode = null;
                    foreach (Match match in releaseMatches) {
                        releaseNode = xmlDocument.CreateNode(XmlNodeType.Element, "Release", string.Empty);

                        if (match.Groups.Count > 0) {

                            XmlNode titleNode = xmlDocument.CreateNode(XmlNodeType.Element, "Title", string.Empty);
                            XmlNode formatNode = xmlDocument.CreateNode(XmlNodeType.Element, "Format", string.Empty);
                            XmlNode releaseDateNode = xmlDocument.CreateNode(XmlNodeType.Element, "ReleaseDate", string.Empty);
                            XmlNode labelNode = xmlDocument.CreateNode(XmlNodeType.Element, "Label", string.Empty);

                            titleNode.InnerText = match.Groups[1].Value.Trim();
                            formatNode.InnerText = match.Groups[2].Value.Trim();

                            if (match.Groups[3].Length > 4) {
                                labelNode.InnerText = match.Groups[4].Value.Trim();
                                releaseDateNode.InnerText = match.Groups[5].Value.Trim();
                            } else {
                                labelNode.InnerText = string.Empty;
                                releaseDateNode.InnerText = match.Groups[3].Value.Trim();
                            }

                            releaseNode.AppendChild(titleNode);
                            releaseNode.AppendChild(formatNode);
                            releaseNode.AppendChild(labelNode);
                            releaseNode.AppendChild(releaseDateNode);

                        }

                        releasesNode.AppendChild(releaseNode);
                    }
                }
            }
        }

        private void conversionBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
            //if (progressForm == null) {
            //    progressForm = new XmlConversionProgressForm();
            //    //  this.Enabled = false;
            //    progressForm.Show();
            //} else {
            //    progressForm.Show();
            //}

            ProcessFiles(e.Argument.ToString());
            //conversionBackgroundWorker.ReportProgress(0);
        }

        //private void conversionBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
        //    if (progressForm != null) {
        //        ProgressBar progressBar = (ProgressBar)progressForm.Controls["xmlConversionProgressBar"];
        //        progressBar.Value = e.ProgressPercentage;
        //    }
        //}

        private void conversionBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
            MessageBox.Show("Conversion Completed.");
        }
    }
}
